package com.linkhub.oms.admin.modules.user.service.impl;
import com.google.common.collect.Lists;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.linkhub.oms.admin.common.exception.ExceptionFactory;
import com.linkhub.oms.admin.modules.satoken.domain.SaUserInfoDTO;
import com.linkhub.oms.admin.modules.satoken.session.LhSessionContext;
import com.linkhub.oms.admin.modules.system.domain.param.SystemSignUpParam;
import com.linkhub.oms.admin.modules.user.account.service.IUserAccountService;
import com.linkhub.oms.admin.modules.user.domain.dto.UserDTO;
import com.linkhub.oms.admin.modules.user.domain.param.MerchantBankCardModifyParam;
import com.linkhub.oms.admin.modules.user.domain.param.MerchantCompanyModifyParam;
import com.linkhub.oms.admin.modules.user.domain.param.MerchantCompanyModifyParamV2;
import com.linkhub.oms.admin.modules.user.domain.param.MerchantEditParam;
import com.linkhub.oms.admin.modules.user.domain.vo.MerchantBankCardVO;
import com.linkhub.oms.admin.modules.user.domain.vo.MerchantCompanyVO;
import com.linkhub.oms.admin.modules.user.domain.vo.MerchantPersonalInfoVO;
import com.linkhub.oms.admin.modules.user.domain.vo.UserInfoWrapper;
import com.linkhub.oms.admin.modules.user.service.UserBizService;
import com.linkhub.oms.common.constant.SaTokenConstant;
import com.linkhub.oms.common.enums.mp.DataStatusEnum;
import com.linkhub.oms.common.enums.mp.RoleCodeEnum;
import com.linkhub.oms.common.util.QtBeanUtil;
import com.linkhub.oms.common.util.QtStreamUtil;
import com.linkhub.oms.component.transactional.service.TransactionalCallBackService;
import com.linkhub.oms.dao.mpservice.*;
import com.linkhub.oms.entity.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Objects;

import static com.linkhub.oms.common.constant.ProjectConstant.ACCOUNT_SESSION_TIME_OUT_SEC;
import static com.linkhub.oms.common.constant.SaTokenConstant.CUSTOMER_WHITE_LIST;

/**
 * @Description: UserBizService
 * @Author: echo
 * @Date: 2024/3/6 22:37
 * @Version: 1.0
 */
@Slf4j
@Service
public class UserBizServiceImpl implements UserBizService {

    @Resource
    private IUserService userService;
    @Resource
    private IUserRoleService userRoleService;
    @Resource
    private TransactionalCallBackService transactionalCallBackService;
    @Resource
    private ICompanyService companyService;
    @Resource
    private ICompanyV2Service companyV2Service;
    @Resource
    private IBankCardService bankCardService;
    @Resource
    private IUserAccountService userAccountService;
    @Resource
    private ITemporaryCodeService temporaryCodeService;

    @Override
    public UserDTO getUserByUserId(String userId) {
        UserEntity user = userService.getUserByUserId(userId);
        if (Objects.isNull(user)) {
            return null;
        }
        UserDTO userDTO = new UserDTO();
        BeanUtil.copyProperties(user, userDTO);

        return userDTO;
    }

    @Override
    public UserDTO getUserByEmail(String email) {
        UserEntity user = userService.getUserByEmail(email);
        if (Objects.isNull(user)) {
            return null;
        }
        UserDTO userDTO = new UserDTO();
        BeanUtil.copyProperties(user, userDTO);

        return userDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String addSignUpCustomer(SystemSignUpParam signUpParam) {
        String userId = IdUtil.getSnowflake().nextIdStr();
        UserEntity userEntity = new UserEntity();
        userEntity.setUserId(userId);
        userEntity.setEmail(signUpParam.getEmail());
        userEntity.setPassword(signUpParam.getPassword());
        userEntity.setCountryDigitalCode(signUpParam.getCountryDigitalCode());
        userEntity.setPhone(signUpParam.getPhone());
        userEntity.setDataStatus(DataStatusEnum.ENABLE);
        userEntity.setUserName(signUpParam.getUserName());

        userService.save(userEntity);
        userRoleService.saveUserRole(userEntity.getUserId(), RoleCodeEnum.CUSTOMER);
        userAccountService.save(UserAccountEntity
                .builder()
                .userId(userEntity.getUserId())
                .build());
        return userId;
    }

    @Override
    public void resetCipher(String email, String password) {
        userService.updatePassWordByEmail(email, password);
    }

    @Override
    public UserInfoWrapper assembleUserInfoInSaSession() {
        SaSession session = StpUtil.getSession();
        SaUserInfoDTO userInfoDTO = LhSessionContext.getUser();
        List<String> userRoles = LhSessionContext.getUserRoles();
        boolean vipCustomer = LhSessionContext.isVipCustomer();
        UserInfoWrapper userInfoWrapper = new UserInfoWrapper();
        userInfoWrapper.setUserId(userInfoDTO.getUserId());
        userInfoWrapper.setEmail(userInfoDTO.getEmail());
        userInfoWrapper.setUserName(userInfoDTO.getUserName());
        userInfoWrapper.setVip(vipCustomer);
        userInfoWrapper.setRoleCodes(userRoles);

        // 首次创建session，则设置过期时间
        if (session.getTimeout() > ACCOUNT_SESSION_TIME_OUT_SEC) {
            session.updateTimeout(ACCOUNT_SESSION_TIME_OUT_SEC);
        }

        return userInfoWrapper;
    }

    @Override
    public List<UserDTO> listMerchants() {
        List<UserEntity> users = userService.listMerchants();
        return QtBeanUtil.copyList(users, UserDTO::new);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserInfo(MerchantEditParam editParam) {
        String userId = editParam.getUserId();
        UserEntity update = new UserEntity();
        update.setUserName(editParam.getUserName());

        userService.updateByUserId(userId, update);
        // 事务提交后
        transactionalCallBackService.syncHandleAfterCommit(this,
                service -> LhSessionContext.removeUserSessionKey(userId, SaSession.USER));

    }

    @Override
    public MerchantPersonalInfoVO getUserPersonalInformation(String userId) {
        UserEntity user = userService.getUserByUserId(userId);
        List<CompanyEntity> companyList = companyService.listByUserId(userId);
        List<BankCardEntity> bankCardList = bankCardService.listByUserId(userId);
        return convertMerchant(user, companyList, bankCardList);
    }

    @Override
    public void modifyCompany(MerchantCompanyModifyParam companyModifyParam) {
        boolean exist = companyService.exist(companyModifyParam.getUserId(),
                companyModifyParam.getId(), companyModifyParam.getCompanyName());
        if (exist) {
            throw ExceptionFactory.getI18nBizException("merchant.company.name.exist.error");
        }
        CompanyEntity companyEntity = new CompanyEntity();
        QtBeanUtil.copyProperties(companyModifyParam, companyEntity);
        companyService.saveOrUpdate(companyEntity);
    }

    @Override
    public void modifyBankCard(MerchantBankCardModifyParam bankCardModifyParam) {
        boolean exist = bankCardService.exist(bankCardModifyParam.getId(), bankCardModifyParam.getCardNumber());
        if (exist) {
            throw ExceptionFactory.getI18nBizException("merchant.card.number.exist.error");
        }
        BankCardEntity bankCard = new BankCardEntity();
        QtBeanUtil.copyProperties(bankCardModifyParam, bankCard);
        bankCardService.saveOrUpdate(bankCard);
    }

    @Override
    public void deleteCompany(Long id) {
        companyService.removeById(id);
    }

    @Override
    public void deleteBankCard(Long id) {
        bankCardService.removeById(id);
    }

    @Override
    public void modifyCompanyV2( MerchantCompanyModifyParamV2 merchantCompanyModifyParamV2 ) {
        String temporaryCode = merchantCompanyModifyParamV2.getTemporaryCode();
        TemporaryCodeEntity temporaryCodeEntity = temporaryCodeService.getByTemporaryCode(temporaryCode);
        if (temporaryCodeEntity == null) {
            throw ExceptionFactory.getI18nBizException("temporaryCode.not.exist.error");
        }
//        Timestamp createdTime = temporaryCodeEntity.getCreatedTime();
//        LocalDateTime createdAt = createdTime.toLocalDateTime();
//        LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
//        if (createdAt.plusHours(SaTokenConstant.TEMPORARY_CODE_EXPIRE_HOURS).isBefore(now)) {
//            throw ExceptionFactory.getI18nBizException("temporaryCode.expire.error");
//        }

        String userId = temporaryCodeEntity.getSourceCode();
        boolean exist = companyV2Service.exist(userId,
                merchantCompanyModifyParamV2.getId(), merchantCompanyModifyParamV2.getCompanyName());
        if (exist) {
            throw ExceptionFactory.getI18nBizException("merchant.companyV2.name.exist.error");
        }
        CompanyV2Entity companyV2Entity = new CompanyV2Entity();
        QtBeanUtil.copyProperties(merchantCompanyModifyParamV2, companyV2Entity);
        companyV2Entity.setUserId(userId);
        companyV2Service.saveOrUpdate(companyV2Entity);
    }


    private MerchantPersonalInfoVO convertMerchant(UserEntity user,
                                                   List<CompanyEntity> companyList,
                                                   List<BankCardEntity> bankCardList) {
        MerchantPersonalInfoVO vo = new MerchantPersonalInfoVO();
        vo.setUserId(user.getUserId());
        vo.setUserName(user.getUserName());
        vo.setEmail(user.getEmail());
        vo.setAvailableBalance("");
        vo.setFrozenBalance("");
        vo.setCredit("0");
        List<MerchantBankCardVO> bankCards = QtStreamUtil.map(bankCardList, bankCard -> {
            MerchantBankCardVO bank = new MerchantBankCardVO();
            QtBeanUtil.copyProperties(bankCard, bank);
            return bank;
        });
        vo.setBankCardList(bankCards);
        vo.setCompanyList(QtBeanUtil.copyList(companyList, MerchantCompanyVO::new));

        return vo;

    }

}
